﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Volo.Abp.DependencyInjection;
using Volo.Abp.ObjectMapping;

namespace Xms.Abp.ObjectMapping;

[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IXmsObjectMapper), typeof(IObjectMapper))]
public class XmsObjectMapper : DefaultObjectMapper, IXmsObjectMapper
{
    public new IXmsAutoObjectMappingProvider AutoObjectMappingProvider { get; }

    public XmsObjectMapper(
        IServiceProvider serviceProvider,
        IXmsAutoObjectMappingProvider autoObjectMappingProvider)
        : base(serviceProvider, autoObjectMappingProvider)
    {
        AutoObjectMappingProvider = autoObjectMappingProvider;
    }

    public TDestination Map<TSource, TDestination>(object source)
    {
        return base.Map<TSource, TDestination>((TSource)source);
    }

    public List<TDestination> Map<TSource, TDestination>(IEnumerable<TSource> source)
    {
        return base.Map<IEnumerable<TSource>, List<TDestination>>(source);
    }

    public TDestination MapTo<TDestination>(object source)
    {
        return source == null ? default : (TDestination)this.Map(source.GetType(), typeof(TDestination), source);
    }

    public List<TDestination> MapTo<TDestination>(IEnumerable source)
    {
        return source == null ? default : (List<TDestination>)this.Map(source.GetType(), typeof(List<TDestination>), source);
    }

    public IQueryable<TDestination> ProjectTo<TSource, TDestination>(IQueryable<TSource> source, params Expression<Func<TDestination, object>>[] membersToExpand)
    {
        return AutoObjectMappingProvider.ProjectTo(source, membersToExpand);
    }

    public IQueryable<TDestination> ProjectTo<TDestination>(IQueryable source, object parameters, params Expression<Func<TDestination, object>>[] membersToExpand)
    {
        return AutoObjectMappingProvider.ProjectTo(source, parameters, membersToExpand);
    }

    public IQueryable<TDestination> ProjectTo<TSource, TDestination>(IQueryable<TSource> source, IDictionary<string, object> parameters, params string[] membersToExpand)
    {
        return AutoObjectMappingProvider.ProjectTo<TSource, TDestination>(source, parameters, membersToExpand);
    }

    public IQueryable ProjectTo(IQueryable source, Type destinationType)
    {
        return AutoObjectMappingProvider.ProjectTo(source, destinationType);
    }

    public IQueryable ProjectTo(IQueryable source, Type destinationType, IDictionary<string, object> parameters, params string[] membersToExpand)
    {
        return AutoObjectMappingProvider.ProjectTo(source, destinationType, parameters, membersToExpand);
    }
}

public class XmsObjectMapper<TContext> : DefaultObjectMapper<TContext>, IXmsObjectMapper<TContext>
{
    public new IXmsAutoObjectMappingProvider AutoObjectMappingProvider { get; }

    public XmsObjectMapper(
        IServiceProvider serviceProvider,
        IXmsAutoObjectMappingProvider<TContext> autoObjectMappingProvider
        ) : base(
            serviceProvider,
            autoObjectMappingProvider)
    {
        AutoObjectMappingProvider = autoObjectMappingProvider;
    }

    public TDestination Map<TSource, TDestination>(object source)
    {
        return base.Map<TSource, TDestination>((TSource)source);
    }

    public List<TDestination> Map<TSource, TDestination>(IEnumerable<TSource> source)
    {
        return base.Map<IEnumerable<TSource>, List<TDestination>>(source);
    }

    public TDestination MapTo<TDestination>(object source)
    {
        return source == null ? default : (TDestination)this.Map(source.GetType(), typeof(TDestination), source);
    }

    public List<TDestination> MapTo<TDestination>(IEnumerable source)
    {
        return source == null ? default : (List<TDestination>)this.Map(source.GetType(), typeof(List<TDestination>), source);
    }

    public IQueryable<TDestination> ProjectTo<TSource, TDestination>(IQueryable<TSource> source, params Expression<Func<TDestination, object>>[] membersToExpand)
    {
        return AutoObjectMappingProvider.ProjectTo(source, membersToExpand);
    }

    public IQueryable<TDestination> ProjectTo<TDestination>(IQueryable source, object parameters, params Expression<Func<TDestination, object>>[] membersToExpand)
    {
        return AutoObjectMappingProvider.ProjectTo(source, parameters, membersToExpand);
    }

    public IQueryable<TDestination> ProjectTo<TSource, TDestination>(IQueryable<TSource> source, IDictionary<string, object> parameters, params string[] membersToExpand)
    {
        return AutoObjectMappingProvider.ProjectTo<TSource, TDestination>(source, parameters, membersToExpand);
    }

    public IQueryable ProjectTo(IQueryable source, Type destinationType)
    {
        return AutoObjectMappingProvider.ProjectTo(source, destinationType);
    }

    public IQueryable ProjectTo(IQueryable source, Type destinationType, IDictionary<string, object> parameters, params string[] membersToExpand)
    {
        return AutoObjectMappingProvider.ProjectTo(source, destinationType, parameters, membersToExpand);
    }
}
